# ①　在模型训练前，需要完成数据集的加载、洗牌和初始化等一系列的相关操作，并实现One-Hot编码    3分
# ②　训练模型需要在训练集上，检验模型需要在测试集上，请按照比例切分，训练集：测试集=3：1    3分
# ③　实现激活函数和其导数的自定义方法 3分
# ④　定义3层网络结构，包括输入层、隐藏层和输出层，并设置相关参数要求学习率0.1  最大迭代次数5000，隐藏层单元数100   3分
# ⑤　实现前向和后向传播过程，包含正确书写代价函数和梯度下降代码  4分
# ⑥　实现准确率的自定义方法，实现训练和预测，并输出测试集的评估指标  3分
# ⑦　输出混淆矩阵和分类报告  4分
import numpy as np
import matplotlib.pyplot as plt


def model(x,theta):
    return x.dot(theta)
def sigmoid(z):
    return 1/(1+np.exp(-z))
def cost(h,y):
    m=len(y)
    return -1/m*np.sum(y*np.log(h)+(1-y)*np.log(1-h))
def FP(x,theta1,theta2):
    a1=x
    z2=model(a1,theta1)
    a2=sigmoid(z2)
    z3=model(a2,theta2)
    a3=sigmoid(z3)
    return a2,a3
def BP(x,y,theta1,theta2,a2,a3,alpha):
    s3=a3-y
    s2=s3.dot(theta2.T)*(a2*(1-a2))

    m=len(y)
    dt2=1/m*a2.T.dot(s3)
    dt1=1/m*x.T.dot(s2)

    theta2-=alpha*dt2
    theta1-=alpha*dt1

    return theta1,theta2
def grad(x,y,alpha=0.1,iter0=500):
    m,n=x.shape
    theta1=np.random.randn(n,100)
    theta2=np.random.randn(100,3)
    J=np.zeros(iter0)
    for i in range(iter0):
        a2, a3=FP(x,theta1,theta2)
        J[i]=cost(a3,y)
        theta1, theta2=BP(x,y,theta1,theta2,a2,a3,alpha)
    return theta1,theta2,a3,J
def score(h,y):
    h_=np.argmax(h,axis=1)
    y_=np.argmax(y,axis=1)
    return np.mean(y_==h_)
if __name__ == '__main__':
    data_x=np.loadtxt('PEPX.txt',delimiter=',')
    data_y=np.loadtxt('PEPL.txt',delimiter=',')
    y_onehot=np.zeros((len(data_x),3))
    data_y=data_y-1
    for i in range(len(data_x)):
        y_onehot[i,int(data_y[i])]=1
    # ①　在模型训练前，需要完成数据集的加载、洗牌和初始化等一系列的相关操作，并实现One - Hot编码
    np.random.seed(666)
    a=np.random.permutation(len(data_x))
    x=data_x[a]
    y=y_onehot[a]

    miu=np.mean(x)
    sigma=np.std(x)
    x=(x-miu)/sigma
    X=np.c_[np.ones(len(x)),x]
    # ②　训练模型需要在训练集上，检验模型需要在测试集上，请按照比例切分，训练集：测试集 = 3：1
    num=int(0.7*len(x))
    train_x,test_x=np.split(X,[num,])
    train_y,test_y=np.split(y,[num,])
    #
    # ③　实现激活函数和其导数的自定义方法
    # 3
    theta1, theta2, a3, J=grad(train_x,train_y)
    plt.plot(J)
    plt.show()
    # 分
    # ④　定义3层网络结构，包括输入层、隐藏层和输出层，并设置相关参数要求学习率0
    # .1
    # 最大迭代次数5000，隐藏层单元数100
    # 3
    # 分
    # ⑤　实现前向和后向传播过程，包含正确书写代价函数和梯度下降代码
    # 4
    # 分
    # ⑥　实现准确率的自定义方法，实现训练和预测，并输出测试集的评估指标
    _,test_h=FP(test_x,theta1,theta2)
    print(score(test_h,test_y))
    # 分
    # ⑦　输出混淆矩阵和分类报告








